import java.io.File;
import java.util.ArrayList;
import java.util.Scanner;

/**
 * @modulename MOTtable
 * @description MOTtable is the default method that builds the MOT table, using 
 * a premade text file. Must be in the format of 6 columns, with headers 
 * 'Binary','Hex','Mnemonic','Operand Type','Description', and 'Action'. 
 * Each column must be separated by a tab. 
 * @callsequence MOTtable testMOT = new MOTtable(File potText); where testMOT is
 *               the given variable name by the user and potText is a File
 *               containing the MOT instructions.
 * @inparam A File containing the MOT directives
 * @outparam Creates a MOTtable table that contains the instruction and
 *           information about the instructions.
 * @errorstested tested using test module at bottom of class
 * @errorsgenerated can not handle empty lines
 * @author Jamie Trefzger
 * @createdate 10/11/09
 * @modlog <p>
 *         <ul>
 *         Who/When/Why
 *         </ul>
 *         Coding Standards Met: "Signed Code Leader(Jaron)"
 *         <p>
 *         Testing Standards Met: "Signed Test Leader(Jamie)"
 */

public class MOTtable{

	private static ArrayList<String> binaryArray;
	private static ArrayList<String> hexArray;
	private static ArrayList<String> mnemonicArray;
	private static ArrayList<String> operandArray;
	private static ArrayList<String> descriptionArray;
	private static ArrayList<String> actionArray;

	public static void startMOTtable() {
		binaryArray = new ArrayList<String>(0);
		hexArray = new ArrayList<String>(0);
		mnemonicArray = new ArrayList<String>(0);
		operandArray = new ArrayList<String>(0);
		descriptionArray = new ArrayList<String>(0);
		actionArray = new ArrayList<String>(0);
		setUp();
	}
	
	private static void setUp() {
		File motTable = new File("src" + Main.systemPathSeparator + "MOTtable.txt");
		String motTableFileString = FileHandler.readFile(motTable);
		Scanner motScanner = new Scanner(motTableFileString);
		String motTableString = new String();
		String tempString = new String();
		// by reading the whole text file into a string, and using newlines as separators
		//we effectively get rid of the newlines
		while (motScanner.hasNextLine()) {
			tempString = motScanner.nextLine();
			motTableString = motTableString + tempString;
		}
		motScanner.close();
		Scanner scanOb1 = new Scanner(motTableString).useDelimiter("\\s*\t\\s*");
		//without newlines, we have a string that used to be 6 columns, each column separated by a tab.
		//this means that if we tab deliminate we can separate the columns into their respective arrays.
		while(scanOb1.hasNext())
		{
			tempString = scanOb1.next();
			binaryArray.add(tempString);
			tempString = scanOb1.next();
			hexArray.add(tempString);
			tempString = scanOb1.next();				
			mnemonicArray.add(tempString);				
			tempString = scanOb1.next();			
			operandArray.add(tempString);
			tempString = scanOb1.next();		
			descriptionArray.add(tempString);
			tempString = scanOb1.next();				
			actionArray.add(tempString);
		}
	}

	/**
	 * @modulename returnBinaryForMnemonic
	 * @description This module returns the binary of a given instruction.
	 * @callsequence testMOT.returnBinaryForMnemonic(String mnemonic); where testMOT is the given variable name by the user.
	 * @inparam mnemonic The op-code that we want to find the binary value of.
	 * @outparam The binary value of the op-code we were given.
	 * @errorstested tested using test module at bottom of class
	 * @errorsgenerated no known errors

	 * @createdate 10/11/09
	 * @modlog <p>
	 *         <ul>
	 *         Who/When/Why 
	 *         </ul>
	 *         Coding Standards Met: "Signed Code Leader(Jaron)"
	 *         <p>
	 *         Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	public static String returnBinaryForMnemonic (String mnemonic) {
		String tempString = new String();
		tempString = mnemonic.toUpperCase();
		int i1 = 0;
		i1 = mnemonicArray.indexOf(tempString);
		tempString = binaryArray.get(i1);
		//System.out.println(i1);
		//System.out.println(tempString);
		return tempString;
	}
	/**
	 * @modulename returnRegisterForMnemonic
	 * @description Returns the Register used with the mnemonic. If no register used, then it it will return null.
	 * @callsequence testMOT.returnRegisterForMnemonic(String mnemonic); where testMOT is the given variable name by the user.
	 * @inparam mnemonic a String that represents the op-code we'll used to determine which register it uses
	 * @outparam Either a two UpperCase-Character String for which register the mnemonic uses, or null.
	 * @errorstested tested using test module at bottom of class
	 * @errorsgenerated no known errors

	 * @createdate 10/11/09
	 * @modlog <p>
	 *         <ul>
	 *         Who/When/Why 
	 *         </ul>
	 *         Coding Standards Met: "Signed Code Leader(Jaron)"
	 *         <p>
	 *         Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	private static String returnRegisterForMnemonic (String mnemonic) {
		String tempMnemonic = new String(mnemonic.toUpperCase());
		if (tempMnemonic.contains("AC")) {
			return "AC";
		} else if (tempMnemonic.contains("IR")) {
			return "IR";
		} else if (tempMnemonic.contains("BR")) {
			return "BR";
		} else if (tempMnemonic.contains("AR")) {
			return "AR";
		} else if (tempMnemonic.contains("PR")) {
			return "PR";
		} else if (tempMnemonic.contains("SR")) {
			return "SR";
		} else {
			return null;
		}
	}
	/**
	 * @modulename usesIR
	 * @description Returns a Boolean value representing whether or not a given instruction uses the IR.
	 * @callsequence testMOT.usesIR(String mnemonic); where testMOT is the given variable name by the user.
	 * @inparam mnemonic a String that represents the op-code 
	 * @outparam a Boolean value representing whether or not a given instruction uses the IR.
	 * @errorstested tested using test module at bottom of class
	 * @errorsgenerated no known errors

	 * @createdate 10/11/09
	 * @modlog <p>
	 *         <ul>
	 *         Who/When/Why 
	 *         </ul>
	 *         Coding Standards Met: "Signed Code Leader(Jaron)"
	 *         <p>
	 *         Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	public static boolean usesIR(String mnemonic) {
		return ("IR" == returnRegisterForMnemonic(mnemonic));
	}
	/**
	 * @modulename usesAR
	 * @description Returns a Boolean value representing whether or not a given instruction uses the AR.
	 * @callsequence testMOT.usesAR(String mnemonic); where testMOT is the given variable name by the user.
	 * @inparam mnemonic a String that represents the op-code 
	 * @outparam a Boolean value representing whether or not a given instruction uses the AR.
	 * @errorstested tested using test module at bottom of class
	 * @errorsgenerated no known errors

	 * @createdate 10/11/09
	 * @modlog <p>
	 *         <ul>
	 *         Who/When/Why 
	 *         </ul>
	 *         Coding Standards Met: "Signed Code Leader(Jaron)"
	 *         <p>
	 *         Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	public static boolean usesAR(String mnemonic) {
		return ("AR" == returnRegisterForMnemonic(mnemonic));
	}
	/**
	 * @modulename usesBR
	 * @description Returns a Boolean value representing whether or not a given instruction uses the BR.
	 * @callsequence testMOT.usesBR(String mnemonic); where testMOT is the given variable name by the user.
	 * @inparam mnemonic a String that represents the op-code 
	 * @outparam a Boolean value representing whether or not a given instruction uses the BR.
	 * @errorstested tested using test module at bottom of class
	 * @errorsgenerated no known errors

	 * @createdate 10/11/09
	 * @modlog <p>
	 *         <ul>
	 *         Who/When/Why 
	 *         </ul>
	 *         Coding Standards Met: "Signed Code Leader(Jaron)"
	 *         <p>
	 *         Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	public static boolean usesBR(String mnemonic) {
		return ("IR" == returnRegisterForMnemonic(mnemonic));
	}
	/**
	 * @modulename usesAC
	 * @description Returns a Boolean value representing whether or not a given instruction uses the AC.
	 * @callsequence testMOT.usesAC(String mnemonic); where testMOT is the given variable name by the user.
	 * @inparam mnemonic a String that represents the op-code 
	 * @outparam a Boolean value representing whether or not a given instruction uses the AC.
	 * @errorstested tested using test module at bottom of class
	 * @errorsgenerated no known errors

	 * @createdate 10/11/09
	 * @modlog <p>
	 *         <ul>
	 *         Who/When/Why 
	 *         </ul>
	 *         Coding Standards Met: "Signed Code Leader(Jaron)"
	 *         <p>
	 *         Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	public static boolean usesAC(String mnemonic) {
		return ("AC" == returnRegisterForMnemonic(mnemonic));
	}
	/**
	 * @modulename usesPR
	 * @description Returns a Boolean value representing whether or not a given instruction uses the PR.
	 * @callsequence testMOT.usesPR(String mnemonic); where testMOT is the given variable name by the user.
	 * @inparam mnemonic a String that represents the op-code 
	 * @outparam a Boolean value representing whether or not a given instruction uses the PR.
	 * @errorstested tested using test module at bottom of class
	 * @errorsgenerated no known errors

	 * @createdate 10/11/09
	 * @modlog <p>
	 *         <ul>
	 *         Who/When/Why 
	 *         </ul>
	 *         Coding Standards Met: "Signed Code Leader(Jaron)"
	 *         <p>
	 *         Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	public static boolean usesPR(String mnemonic) {
		return ("PR" == returnRegisterForMnemonic(mnemonic));
	}
	/**
	 * @modulename usesSR
	 * @description Returns a Boolean value representing whether or not a given instruction uses the SR.
	 * @callsequence testMOT.usesSR(String mnemonic); where testMOT is the given variable name by the user.
	 * @inparam mnemonic a String that represents the op-code 
	 * @outparam a Boolean value representing whether or not a given instruction uses the SR.
	 * @errorstested tested using test module at bottom of class
	 * @errorsgenerated no known errors

	 * @createdate 10/11/09
	 * @modlog <p>
	 *         <ul>
	 *         Who/When/Why 
	 *         </ul>
	 *         Coding Standards Met: "Signed Code Leader(Jaron)"
	 *         <p>
	 *         Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	public static boolean usesSR(String mnemonic) {
		return ("SR" == returnRegisterForMnemonic(mnemonic));
	}
	/**
	 * @modulename returnHexForMnemonic
	 * @description This module returns the hex of a given instruction.
	 * @callsequence testMOT.returnHexForMnemonic(String mnemonic); where testMOT is the given variable name by the user.
	 * @inparam mnemonic The op-code that we want to find the hex value of.
	 * @outparam The hex value of the op-code we were given.
	 * @errorstested tested using test module at bottom of class
	 * @errorsgenerated no known errors

	 * @createdate 10/11/09
	 * @modlog <p>
	 *         <ul>
	 *         Who/When/Why 
	 *         </ul>
	 *         Coding Standards Met: "Signed Code Leader(Jaron)"
	 *         <p>
	 *         Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	public static String returnHexForMnemonic (String mnemonic) {
		String tempString = new String();
		tempString = mnemonic.toUpperCase();
		int i1 = 0;
		i1 = mnemonicArray.indexOf(tempString);
		tempString = hexArray.get(i1);
		//System.out.println(i1);
		//System.out.println(tempString);
		return tempString;
	}
	/**
	 * @modulename returnOperandForMnemonic
	 * @description Returns the operand type for the given mnemonic.
	 * @callsequence testMOT.returnRegisterForMnemonic(String mnemonic); where testMOT is the given variable name by the user.
	 * @inparam mnemonic The op-code that we want to find the operand type of.
	 * @outparam The operand type of the op-code we were given.
	 * @errorstested tested using test module at bottom of class
	 * @errorsgenerated no known errors

	 * @createdate 10/11/09
	 * @modlog <p>
	 *         <ul>
	 *         Who/When/Why 
	 *         </ul>
	 *         Coding Standards Met: "Signed Code Leader(Jaron)"
	 *         <p>
	 *         Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	public static String returnOperandForMnemonic (String mnemonic) {
		String tempString = new String();
		tempString = mnemonic.toUpperCase();
		int i1 = 0;
		i1 = mnemonicArray.indexOf(tempString);
		tempString = operandArray.get(i1);
		//System.out.println(i1);
		//System.out.println(tempString);
		return tempString;
	}
	/**
	 * @modulename returnDescriptionForMnemonic
	 * @description Returns the description for the given mnemonic.
	 * @callsequence testMOT.returnDescriptionForMnemonic(String mnemonic); where testMOT is the given variable name by the user.
	 * @inparam mnemonic The op-code that we want to find the description of.
	 * @outparam The description of the op-code we were given.
	 * @errorstested tested using test module at bottom of class
	 * @errorsgenerated no known errors

	 * @createdate 10/11/09
	 * @modlog <p>
	 *         <ul>
	 *         Who/When/Why 
	 *         </ul>
	 *         Coding Standards Met: "Signed Code Leader(Jaron)"
	 *         <p>
	 *         Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	public static String returnDescriptionForMnemonic (String mnemonic) {
		String tempString = new String();
		tempString = mnemonic.toUpperCase();
		int i1 = 0;
		i1 = mnemonicArray.indexOf(tempString);
		tempString = descriptionArray.get(i1);
		//System.out.println(i1);
		//System.out.println(tempString);
		return tempString;
	}
	/**
	 * @modulename returnActionForMnemonic
	 * @description Returns the action for the given mnemonic.
	 * @callsequence testMOT.returnActionForMnemonic(String mnemonic); where testMOT is the given variable name by the user.
	 * @inparam mnemonic The op-code that we want to find the action of.
	 * @outparam The action of the op-code we were given.
	 * @errorstested tested using test module at bottom of class
	 * @errorsgenerated no known errors

	 * @createdate 10/11/09
	 * @modlog <p>
	 *         <ul>
	 *         Who/When/Why 
	 *         </ul>
	 *         Coding Standards Met: "Signed Code Leader(Jaron)"
	 *         <p>
	 *         Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	public static String returnActionForMnemonic (String mnemonic) {
		String tempString = new String();
		tempString = mnemonic.toUpperCase();
		int i1 = 0;
		i1 = mnemonicArray.indexOf(tempString);
		tempString = actionArray.get(i1);
		//System.out.println(i1);
		//System.out.println(tempString);
		return tempString;
	}
	/**
	 * @modulename mnemonicIsDefined
	 * @description Checks to see if the given mnemonic exists in the MOT table.
	 * @callsequence testMOT.mnemonicIsDefined(String mnemonic); where testMOT is the given variable name by the user.
	 * @inparam mnemonic A string containing the mnemonic you are unsure exists in the MOT table.
	 * @outparam A boolean which returns true if the mnemonic is defined, false otherwise.
	 * @errorstested tested using test module at bottom of class
	 * @errorsgenerated no known errors

	 * @createdate 10/11/09
	 * @modlog <p>
	 *         <ul>
	 *         Who/When/Why 
	 *         </ul>
	 *         Coding Standards Met: "Signed Code Leader(Jaron)"
	 *         <p>
	 *         Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	public static Boolean mnemonicIsDefined (String mnemonic) {
		//System.out.println("MNEMONIC GIVEN: " + mnemonic);
		if (mnemonic != null) {
			String tempString = mnemonic.toUpperCase();
			return mnemonicArray.contains(tempString);
		} else {
			return Boolean.FALSE;
		}
	}
	
	//test module
	public static void main(String[] args) {
		MOTtable.startMOTtable();

		System.out.println();
		System.out.println("test1");
		// tests the 'return' functions
		System.out.println("Mnemonic: LD-AC");
		System.out.print("Binary: ");
		System.out.println(returnBinaryForMnemonic("LD-AC"));
		System.out.print("Hex: ");
		System.out.println(returnHexForMnemonic("LD-AC"));
		System.out.print("Operand: ");
		System.out.println(returnOperandForMnemonic("LD-AC"));
		System.out.print("Description: ");
		System.out.println(returnDescriptionForMnemonic("LD-AC"));
		System.out.print("Action: ");
		System.out.println(returnActionForMnemonic("LD-AC"));
		System.out.println("Test1 passed.");

		System.out.println();
		System.out.println("test2");
		// tests the 'return' functions for lower case functionality
		System.out.println("Mnemonic: ld-ac");
		System.out.print("Binary: ");
		System.out.println(returnBinaryForMnemonic("ld-ac"));
		System.out.print("Hex: ");
		System.out.println(returnHexForMnemonic("ld-ac"));
		System.out.print("Operand: ");
		System.out.println(returnOperandForMnemonic("ld-ac"));
		System.out.print("Description: ");
		System.out.println(returnDescriptionForMnemonic("ld-ac"));
		System.out.print("Action: ");
		System.out.println(returnActionForMnemonic("ld-ac"));
		System.out.println("Test2 passed.");

		System.out.println();
		System.out.println("test3");
		// tests the 'return' functions for mixed case functionality
		System.out.println("Mnemonic: Ld-AC");
		System.out.print("Binary: ");
		System.out.println(returnBinaryForMnemonic("Ld-AC"));
		System.out.print("Hex: ");
		System.out.println(returnHexForMnemonic("Ld-AC"));
		System.out.print("Operand: ");
		System.out.println(returnOperandForMnemonic("Ld-AC"));
		System.out.print("Description: ");
		System.out.println(returnDescriptionForMnemonic("Ld-AC"));
		System.out.print("Action: ");
		System.out.println(returnActionForMnemonic("Ld-AC"));
		System.out.println("Test3 passed.");


		System.out.println();
		System.out.println("test4");
		// tests the mnemonicIsDefined function for true and false values.
		System.out.println("is the instruction in the table?"+ mnemonicIsDefined("ld-ac"));
		System.out.println("is the instruction in the table?"+ mnemonicIsDefined("WrongMnemonic"));
		System.out.println("Test4 passed.");

		System.out.println();
		System.out.println("test5");
		//tests the constructor when an empty file is passed.
		//File emptyMotFile = new File("Assembler\\EmptyTextFile.txt");
		//MOTtable emptyMotObject = new MOTtable(emptyMotFile);
		System.out.println("Test5 passed.");

		System.out.println();
		System.out.println("test6");
		// use the commands on the constructed empty object.
		// All throw an error, because they don't check for the empty string case.
		//throw error here, or elsewhere?
		//		System.out.println("Mnemonic: (empty string)");
		//		System.out.print("Binary: ");
		//		System.out.println(emptyMotObject.returnBinaryForMnemonic(""));
		//		System.out.print("Hex: ");
		//		System.out.println(emptyMotObject.returnHexForMnemonic(""));
		//		System.out.print("Operand: ");
		//		System.out.println(emptyMotObject.returnOperandForMnemonic(""));
		//		System.out.print("Description: ");
		//		System.out.println(emptyMotObject.returnDescriptionForMnemonic(""));
		//		System.out.print("Action: ");
		//		System.out.println(emptyMotObject.returnActionForMnemonic(""));
		System.out.println("test6 undecided.");

		System.out.println();
		System.out.println("test7");
		// test the commands on an empty string for the mnemonic
		// throw error here, or check it elsewhere?
		//		System.out.println("Mnemonic: (empty string)");
		//		System.out.print("Binary: ");
		//		System.out.println(returnBinaryForMnemonic(""));
		//		System.out.print("Hex: ");
		//		System.out.println(returnHexForMnemonic(""));
		//		System.out.print("Operand: ");
		//		System.out.println(returnOperandForMnemonic(""));
		//		System.out.print("Description: ");
		//		System.out.println(returnDescriptionForMnemonic(""));
		//		System.out.print("Action: ");
		//		System.out.println(returnActionForMnemonic(""));
		System.out.println("Test7 undecided.");

		System.out.println();
		System.out.println("test8");
		// test the commands on an empty string for the mnemonic
		// throw error here, or check it elsewhere?
		//		System.out.println("Mnemonic: nonexistentMnemonic");
		//		System.out.print("Binary: ");
		//		System.out.println(returnBinaryForMnemonic("nonexistentMnemonic"));
		//		System.out.print("Hex: ");
		//		System.out.println(returnHexForMnemonic("nonexistentMnemonic"));
		//		System.out.print("Operand: ");
		//		System.out.println(returnOperandForMnemonic("nonexistentMnemonic"));
		//		System.out.print("Description: ");
		//		System.out.println(returnDescriptionForMnemonic("nonexistentMnemonic"));
		//		System.out.print("Action: ");
		//		System.out.println(returnActionForMnemonic("nonexistentMnemonic"));
		System.out.println("Test8 undecided.");

		//feel free to add test cases here if i missed any.


	}

	/**
	 * Given a instruction name which is defined in the MOTtable, <code>directive</code>, this method
	 * returns the operand type of <code>instruction</code>.
	 * @param instruction the name of the instruction.
	 * @return an operandType variable which represents what type of operands an instruction is 
	 * allowed to have
	 */
	public static OperandType.operandType operandType(String instruction) {
		String higher = instruction.toUpperCase();
		String typeString = operandArray.get(mnemonicArray.indexOf(higher));
		if (typeString.equals("type 1")) {
			return OperandType.operandType.TYPE1;
		} else if (typeString.equals("type 2")) {
			return OperandType.operandType.TYPE2;
		} else if (typeString.equals("type 3")) {
			return OperandType.operandType.TYPE3;
		} else if (typeString.equals("type 4")) {
			return OperandType.operandType.TYPE4;
		} else if (typeString.equals("EXPRESSION 1")) {
			return OperandType.operandType.EXPRESSION1;
		} else if (typeString.equals("EXPRESSION 2")) {
			return OperandType.operandType.EXPRESSION2;
		} else if (typeString.equals("EXPRESSION 3")) {
			return OperandType.operandType.EXPRESSION1;
		} else if (typeString.equals("REF-ALL")) {
			return OperandType.operandType.REFALL;
		} else if (typeString.equalsIgnoreCase("Reference")) {
			return OperandType.operandType.REF1;
		} else if (typeString.equals("#Reference")) {
			return OperandType.operandType.REF2;
		} else if (typeString.equals("%Reference")) {
			return OperandType.operandType.REF3;
		} else if (typeString.equals("Reference-Exp")) {
			return OperandType.operandType.REFEXP;
		} else if (typeString.equals("On or Off")) {
			return OperandType.operandType.ONOFF;
		} else if (typeString.equals("label,label,label,label")) {
			return OperandType.operandType.LABEL;
		} else if (typeString.equals("ex-label,ex-label,ex-label,ex-label")) {
			return OperandType.operandType.EXLABEL;
		} else if (typeString.equals("base 10 number right justified")) {
			return OperandType.operandType.NUM;
		} else if (typeString.equals("'ccc' left justified")) {
			return OperandType.operandType.CHR;
		} else if (typeString.equals("hex string right justified")) {
			return OperandType.operandType.HEX;
		} else if (typeString.equals("binary string right justified")) {
			return OperandType.operandType.BIN;
		} else if (typeString.equals("Adress constant")) {
			return OperandType.operandType.ADDR;
		}else if (typeString.equals("*")) {
			return OperandType.operandType.STAR;
		}
		return OperandType.operandType.NONE;
	}
}